//
// Created by 19594 on 25-6-4.
//

#include "LCD.h"
#include "spi.h"
#include "Font.h"
_lcd_dev lcddev;
uint16_t POINT_COLOR = 0x0000,BACK_COLOR = 0xFFFF;  
uint16_t DeviceCode;	
void LCD_WriteCommand(uint8_t command) {
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,0);
    HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,0);
    HAL_SPI_Transmit(&hspi1,&command,1,100);
    HAL_GPIO_WritePin(CS_GPIO_Port,CS_Pin,1);
}
void LCD_WriteData(uint8_t data) {
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,0);
    HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,1);
    HAL_SPI_Transmit(&hspi1,&data,1,100);
    HAL_GPIO_WritePin(CS_GPIO_Port,CS_Pin,1);
}
void LCD_WriteReg(uint8_t reg, uint8_t data) {
	LCD_WriteCommand(reg);
	LCD_WriteData(data);
}
void LCD_WriteData16(uint16_t data) {
    uint8_t temp[2];
	temp[0]=data>>8;
	temp[1]=data;
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,0);
    HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,1);
    HAL_SPI_Transmit(&hspi1,temp,2,100);
    HAL_GPIO_WritePin(CS_GPIO_Port,CS_Pin,1);
}
void LCD_RESET() {
    HAL_GPIO_WritePin(RES_GPIO_Port,RES_Pin,0);
    HAL_Delay(100);
    HAL_GPIO_WritePin(RES_GPIO_Port,RES_Pin,1);
    HAL_Delay(100);
}
void LCD_WriteRam_prepare() {
	LCD_WriteCommand(lcddev.wramcmd);
}
void LCD_Clear(uint16_t Color)
{
	unsigned int i,m;  
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);
	HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin,0);
	HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,1);

	for(i=0;i<lcddev.height;i++)
	{
		for(m=0;m<lcddev.width;m++)
		{	
			LCD_WriteData16(Color);
		}
	}
	HAL_GPIO_WritePin(CS_GPIO_Port,CS_Pin,1);
}
void LCD_Init() {
    LCD_RESET(); //Reset before LCD Init.
 
	LCD_WriteCommand(0xCF);  
	LCD_WriteData(0x00); 
	LCD_WriteData(0xD9); //0xC1 
	LCD_WriteData(0X30); 
	LCD_WriteCommand(0xED);  
	LCD_WriteData(0x64); 
	LCD_WriteData(0x03); 
	LCD_WriteData(0X12); 
	LCD_WriteData(0X81); 
	LCD_WriteCommand(0xE8);  
	LCD_WriteData(0x85); 
	LCD_WriteData(0x10); 
	LCD_WriteData(0x7A); 
	LCD_WriteCommand(0xCB);  
	LCD_WriteData(0x39); 
	LCD_WriteData(0x2C); 
	LCD_WriteData(0x00); 
	LCD_WriteData(0x34); 
	LCD_WriteData(0x02); 
	LCD_WriteCommand(0xF7);  
	LCD_WriteData(0x20); 
	LCD_WriteCommand(0xEA);  
	LCD_WriteData(0x00); 
	LCD_WriteData(0x00); 
	LCD_WriteCommand(0xC0);    //Power control 
	LCD_WriteData(0x1B);   //VRH[5:0] 
	LCD_WriteCommand(0xC1);    //Power control 
	LCD_WriteData(0x12);   //SAP[2:0];BT[3:0] 0x01
	LCD_WriteCommand(0xC5);    //VCM control 
	LCD_WriteData(0x08); 	 //30
	LCD_WriteData(0x26); 	 //30
	LCD_WriteCommand(0xC7);    //VCM control2 
	LCD_WriteData(0XB7); 
	LCD_WriteCommand(0x36);    // Memory Access Control 
	LCD_WriteData(0x08); 
	LCD_WriteCommand(0x3A);   
	LCD_WriteData(0x55); 
	LCD_WriteCommand(0xB1);   
	LCD_WriteData(0x00);   
	LCD_WriteData(0x1A); 
	LCD_WriteCommand(0xB6);    // Display Function Control 
	LCD_WriteData(0x0A); 
	LCD_WriteData(0xA2); 
	LCD_WriteCommand(0xF2);    // 3Gamma Function Disable 
	LCD_WriteData(0x00); 
	LCD_WriteCommand(0x26);    //Gamma curve selected 
	LCD_WriteData(0x01); 
	LCD_WriteCommand(0xE0);    //Set Gamma 
	LCD_WriteData(0x0F); 
	LCD_WriteData(0x1D); 
	LCD_WriteData(0x1A); 
	LCD_WriteData(0x0A); 
	LCD_WriteData(0x0D); 
	LCD_WriteData(0x07); 
	LCD_WriteData(0x49); 
	LCD_WriteData(0X66); 
	LCD_WriteData(0x3B); 
	LCD_WriteData(0x07); 
	LCD_WriteData(0x11); 
	LCD_WriteData(0x01); 
	LCD_WriteData(0x09); 
	LCD_WriteData(0x05); 
	LCD_WriteData(0x04); 		 
	LCD_WriteCommand(0XE1);    //Set Gamma 
	LCD_WriteData(0x00); 
	LCD_WriteData(0x18); 
	LCD_WriteData(0x1D); 
	LCD_WriteData(0x02); 
	LCD_WriteData(0x0F); 
	LCD_WriteData(0x04); 
	LCD_WriteData(0x36); 
	LCD_WriteData(0x13); 
	LCD_WriteData(0x4C); 
	LCD_WriteData(0x07); 
	LCD_WriteData(0x13); 
	LCD_WriteData(0x0F); 
	LCD_WriteData(0x2E); 
	LCD_WriteData(0x2F); 
	LCD_WriteData(0x05); 
	LCD_WriteCommand(0x2B); 
	LCD_WriteData(0x00);
	LCD_WriteData(0x00);
	LCD_WriteData(0x01);
	LCD_WriteData(0x3f);
	LCD_WriteCommand(0x2A); 
	LCD_WriteData(0x00);
	LCD_WriteData(0x00);
	LCD_WriteData(0x00);
	LCD_WriteData(0xef);	 
	LCD_WriteCommand(0x11); //Exit Sleep
	HAL_Delay(120);
	LCD_WriteCommand(0x29); //display on
	LCD_direction(USE_HORIZONTAL);
	HAL_GPIO_WritePin(BL_GPIO_Port,BL_Pin,1);
	LCD_Clear(WHITE);


}
void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
{	
	LCD_WriteCommand(lcddev.setxcmd);	
	LCD_WriteData(xStar>>8);
	LCD_WriteData(0x00FF&xStar);		
	LCD_WriteData(xEnd>>8);
	LCD_WriteData(0x00FF&xEnd);

	LCD_WriteCommand(lcddev.setycmd);	
	LCD_WriteData(yStar>>8);
	LCD_WriteData(0x00FF&yStar);		
	LCD_WriteData(yEnd>>8);
	LCD_WriteData(0x00FF&yEnd);

	LCD_WriteRam_prepare();	//¿ªÊ¼Ð´ÈëGRAM			
}
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
	LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);
}
void LCD_direction(uint8_t direction)
{
	lcddev.setxcmd=0x2A;
	lcddev.setycmd=0x2B;
	lcddev.wramcmd=0x2C;
	switch(direction){
		case 0:
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;
			LCD_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0
			break;
		case 1:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,(1<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
			break;
		case 2:
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;
			LCD_WriteReg(0x36,(1<<3)|(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0
			break;
		case 3:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
			break;
		default:break;
	}
}
void GUI_DrawPoint(uint16_t x,uint16_t y,uint16_t color)
{
	LCD_SetCursor(x,y);//设置光标位置
	LCD_WriteData16(color);
}
void LCD_DrawPoint(uint16_t x,uint16_t y)
{
	LCD_SetCursor(x,y);//设置光标位置
	LCD_WriteData16(POINT_COLOR);
}
void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color)
{
	uint16_t i,j;
	uint16_t width=ex-sx+1; 		//µÃµ½Ìî³äµÄ¿í¶È
	uint16_t height=ey-sy+1;		//¸ß¶È
	LCD_SetWindows(sx,sy,ex,ey);//ÉèÖÃÏÔÊ¾´°¿Ú
	for(i=0;i<height;i++)
	{
		for(j=0;j<width;j++)
			LCD_WriteData16(color);	//Ð´ÈëÊý¾Ý
	}
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//»Ö¸´´°¿ÚÉèÖÃÎªÈ«ÆÁ
}
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	uint16_t t;
	int xerr=0,yerr=0,delta_x,delta_y,distance;
	int incx,incy,uRow,uCol;

	delta_x=x2-x1; //¼ÆËã×ø±êÔöÁ¿
	delta_y=y2-y1;
	uRow=x1;
	uCol=y1;
	if(delta_x>0)incx=1; //ÉèÖÃµ¥²½·½Ïò
	else if(delta_x==0)incx=0;//´¹Ö±Ïß
	else {incx=-1;delta_x=-delta_x;}
	if(delta_y>0)incy=1;
	else if(delta_y==0)incy=0;//Ë®Æ½Ïß
	else{incy=-1;delta_y=-delta_y;}
	if( delta_x>delta_y)distance=delta_x; //Ñ¡È¡»ù±¾ÔöÁ¿×ø±êÖá
	else distance=delta_y;
	for(t=0;t<=distance+1;t++ )//»­ÏßÊä³ö
	{
		LCD_DrawPoint(uRow,uCol);//»­µã
		xerr+=delta_x ;
		yerr+=delta_y ;
		if(xerr>distance)
		{
			xerr-=distance;
			uRow+=incx;
		}
		if(yerr>distance)
		{
			yerr-=distance;
			uCol+=incy;
		}
	}
}
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	LCD_DrawLine(x1,y1,x2,y1);
	LCD_DrawLine(x1,y1,x1,y2);
	LCD_DrawLine(x1,y2,x2,y2);
	LCD_DrawLine(x2,y1,x2,y2);
}
void LCD_DrawFillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	LCD_Fill(x1,y1,x2,y2,POINT_COLOR);
}
void _draw_circle_8(int xc, int yc, int x, int y, uint16_t c)
{
	GUI_DrawPoint(xc + x, yc + y, c);

	GUI_DrawPoint(xc - x, yc + y, c);

	GUI_DrawPoint(xc + x, yc - y, c);

	GUI_DrawPoint(xc - x, yc - y, c);

	GUI_DrawPoint(xc + y, yc + x, c);

	GUI_DrawPoint(xc - y, yc + x, c);

	GUI_DrawPoint(xc + y, yc - x, c);

	GUI_DrawPoint(xc - y, yc - x, c);
}
void gui_circle(int xc, int yc,uint16_t c,int r, int fill)
{
	int x = 0, y = r, yi, d;

	d = 3 - 2 * r;


	if (fill)
	{
		// Èç¹ûÌî³ä£¨»­ÊµÐÄÔ²£©
		while (x <= y) {
			for (yi = x; yi <= y; yi++)
				_draw_circle_8(xc, yc, x, yi, c);

			if (d < 0) {
				d = d + 4 * x + 6;
			} else {
				d = d + 4 * (x - y) + 10;
				y--;
			}
			x++;
		}
	} else
	{
		// Èç¹û²»Ìî³ä£¨»­¿ÕÐÄÔ²£©
		while (x <= y) {
			_draw_circle_8(xc, yc, x, y, c);
			if (d < 0) {
				d = d + 4 * x + 6;
			} else {
				d = d + 4 * (x - y) + 10;
				y--;
			}
			x++;
		}
	}
}
void Draw_Triangel(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
	LCD_DrawLine(x0,y0,x1,y1);
	LCD_DrawLine(x1,y1,x2,y2);
	LCD_DrawLine(x2,y2,x0,y0);
}

// static void _swap(uint16_t *a, uint16_t *b)
// {
// 	uint16_t tmp;
// 	tmp = *a;
// 	*a = *b;
// 	*b = tmp;
// }
void LCD_ShowChar(uint16_t x,uint16_t y,uint16_t fc, uint16_t bc, uint8_t num,uint8_t size,uint8_t mode)
{
	uint8_t temp;
	uint8_t pos,t;
	uint16_t colortemp=POINT_COLOR;

	num=num-' ';//偏移量
	LCD_SetWindows(x,y,x+size/2-1,y+size-1);//设置显示窗口
	if(!mode) //非叠加模式
	{
		for(pos=0;pos<size;pos++)
		{
			if(size==12)temp=asc2_1206[num][pos];//调用1206字体
			else temp=asc2_1608[num][pos];		 //调用1608字体
			for(t=0;t<size/2;t++)
			{
				if(temp&0x01)LCD_WriteData16(fc);
				else LCD_WriteData16(bc);
				temp>>=1;

			}

		}
	}else//µþ¼Ó·½Ê½
	{
		for(pos=0;pos<size;pos++)
		{
			if(size==12)temp=asc2_1206[num][pos];//µ÷ÓÃ1206×ÖÌå
			else temp=asc2_1608[num][pos];		 //µ÷ÓÃ1608×ÖÌå
			for(t=0;t<size/2;t++)
			{
				POINT_COLOR=fc;
				if(temp&0x01)LCD_DrawPoint(x+t,y+pos);//»­Ò»¸öµã
				temp>>=1;
			}
		}
	}
	POINT_COLOR=colortemp;
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//»Ö¸´´°¿ÚÎªÈ«ÆÁ
}
void LCD_ShowString(uint16_t x,uint16_t y,uint8_t size,uint8_t *p,uint8_t mode)
{
	while((*p<='~')&&(*p>=' '))//ÅÐ¶ÏÊÇ²»ÊÇ·Ç·¨×Ö·û!
	{
		if(x>(lcddev.width-1)||y>(lcddev.height-1))
			return;
		LCD_ShowChar(x,y,POINT_COLOR,BACK_COLOR,*p,size,mode);
		x+=size/2;
		p++;
	}
}
uint32_t mypow(uint8_t m,uint8_t n)
{
	uint32_t result=1;	 
	while(n--)result*=m;    
	return result;
}
void LCD_ShowNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t size)
{
	uint8_t t,temp;
	uint8_t enshow=0;
	for(t=0;t<len;t++)
	{
		temp=(num/mypow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				LCD_ShowChar(x+(size/2)*t,y,POINT_COLOR,BACK_COLOR,' ',size,0);
				continue;
			}else enshow=1;

		}
		LCD_ShowChar(x+(size/2)*t,y,POINT_COLOR,BACK_COLOR,temp+'0',size,0);
	}
}
void Gui_Drawbmp16(uint16_t x,uint16_t y,uint16_t height,uint16_t width,const unsigned char *p)
{
	int i;
	unsigned char picH,picL;
	LCD_SetWindows(x,y,x+width-1,y+height-1);//´°¿ÚÉèÖÃ
	for(i=0;i<width*height;i++)
	{
		picL=*(p+i*2);	//数据低位在前
		picH=*(p+i*2+1);
		LCD_WriteData16(picH<<8|picL);
	}
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复显示窗口为全屏
}